package com.gitee.wsl.mathematics.geometry.d2.triangle

import com.gitee.wsl.mathematics.coordinate.d2.Coordinate2
import com.gitee.wsl.mathematics.geometry.api.TriangleShape
import com.gitee.wsl.mathematics.geometry.d2.CloseShape2d
import com.gitee.wsl.mathematics.geometry.d2.LineListShape2d
import com.gitee.wsl.mathematics.geometry.d2.line.LineShape2d
import com.gitee.wsl.mathematics.number.compareTo
import com.gitee.wsl.mathematics.vector.ext.distanceTo
import com.gitee.wsl.unit.angle.AngleUnit
import com.gitee.wsl.unit.angle.ext.minus
import com.gitee.wsl.unit.angle.ext.plus


interface TriangleShape2d<T:Number,V: Coordinate2<T, V>>: TriangleShape<T, V>, CloseShape2d<T, V>,
    LineListShape2d<T, V> {

    override val lines get() = listOf(ab,ac,ca)

    override val ab: LineShape2d<T, V>  get() = createLine(a,b)
    override val ac: LineShape2d<T, V>  get() = createLine(a,c)
    override val bc: LineShape2d<T, V>  get() = createLine(b,c)

    val ca: LineShape2d<T, V>  get() = createLine(c,a)

    val A:T get() =  ab.perimeter
    val B:T get() =  bc.perimeter
    val C:T get() =  ac.perimeter

    val uA:AngleUnit get() = cosUgol(B,C,A)
    val uB:AngleUnit get() = cosUgol(C,A,B)
    val uC:AngleUnit get() = AngleUnit.PI - (uA + uB)

    override fun createLine(a:V, b:V):LineShape2d<T,V>

    override val center: V
        get() = createPoint2 (((a.x) + (b.x) + (c.x)) / 3,((a.y) + (b.y) + (c.y)) / 3)

    fun isTriangle(): Boolean {
        return A + B > C && A + C > B && B + C > A && uA > AngleUnit.ZERO && uB > AngleUnit.ZERO && uC > AngleUnit.ZERO
    }

    override val area: T
        get() = _getArea(a,b,c)

    override fun containsPoint(p: Coordinate2<T, *>): Boolean {
         return abs(
             area - (_getArea(p, b, c) +
                        _getArea(a, p, c) +
                        _getArea(a, b, p))
                ).isApproxZero()
    }

    override val perimeter: T
        get() = ab.perimeter+ac.perimeter+bc.perimeter

    //计算3m边角
    private fun cosUgol(storona1: T, storona2: T, storona3: T): AngleUnit {
        return AngleUnit.Degrees(acos((sqr(storona1) + sqr(storona2) - sqr(storona3)) / (2 * storona1 * storona2)))
    }

    /**
     * Returns true if the given vertex is one of the vertices describing this
     * triangle.
     *
     * @param vertex
     * The vertex to be tested
     * @return Returns true if the Vertex is one of the vertices describing this
     * triangle
     */
    fun hasVertex(vertex:Coordinate2<T, *>): Boolean {
        return a == vertex || b == vertex || c == vertex
    }


}

//获取面积
private fun<T:Number> _getArea(p1: Coordinate2<T, *>, p2: Coordinate2<T, *>, p3: Coordinate2<T, *>): T {
    p1.run {
    val side1 = p1.distanceTo(p3)
    val side2 = p1.distanceTo(p2)
    val side3 = p2.distanceTo(p3)
    val s = (side1 + side2 + side3) / 2
    return sqrt(s * (s - side1) * (s - side2) * (s - side3))
   }
}